﻿#region Using
using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;
using Microsoft.Xna.Framework.Net;
using Microsoft.Xna.Framework.Storage;
#endregion Using

namespace LloydGame
{
    public class GameLight : GameComponent
    {
        #region Class Fields
        protected Vector3 m_position;
        protected float m_falloffStart;
        protected float m_falloffEnd;

        protected Vector3 m_color;

        protected GameObject m_attachedTo;
        protected Vector3 m_offset;
        protected Vector3 m_orriginalOffset;

        protected ShadowMap m_shadowMap;

        protected bool m_createStaticShadowMap;
        #endregion Class Fields

        #region Properties
        public Vector3 position
        {
            get
            {
                return m_position;
            }
        }

        public float falloffEnd
        {
            get
            {
                return m_falloffEnd;
            }
        }

        public Texture shadowMap
        {
            get
            {
                if (m_shadowMap == null)
                {
                    return null;
                }

                return m_shadowMap.shadowMap;
            }
        }
        #endregion Properties

        // constructor
        public GameLight(Game p_game, Vector3 p_position, float p_falloffStart, float p_falloffEnd, Vector3 p_color, int p_shadowMapSize)
            : base(p_game)
        {
            m_position = p_position;
            m_falloffStart = p_falloffStart;
            m_falloffEnd = p_falloffEnd;

            m_color = p_color;

            m_createStaticShadowMap = true;

            p_game.Components.Add(this);
        }

        // attach the light to a gameobject with an offset
        public void attachTo(GameObject p_gameObject, Vector3 p_offset)
        {
            m_attachedTo = p_gameObject;
            m_offset = p_offset;
            m_orriginalOffset = m_offset;

            moveLight();
        }

        // update light
        public void update(GameTime p_gameTime)
        {
            if (m_attachedTo != null)
            {
                moveLight();
            }
            else
            {
                animateLight(p_gameTime);
            }

            if (m_shadowMap != null)
            {
                if (m_createStaticShadowMap)
                {
                    m_shadowMap.createShadowMap(p_gameTime, this, true);

                    m_createStaticShadowMap = false;
                }
                else
                {
                    m_shadowMap.createShadowMap(p_gameTime, this, false);
                }
            }
        }

        // move the light according to the gameobject it is attached to
        protected virtual void moveLight()
        {
            Matrix rot = Matrix.CreateFromYawPitchRoll(
                m_attachedTo.rotation.Y,
                m_attachedTo.rotation.X,
                m_attachedTo.rotation.Z);

            Vector3 offset = Vector3.Transform(m_orriginalOffset, rot);

            Vector3 position = m_attachedTo.position + m_offset;

            if (position != m_position || offset != m_offset)
            {
                m_createStaticShadowMap = true;

                m_position = position;
                m_offset = offset;
            }
        }


        protected virtual void animateLight(GameTime p_gameTime)
        {
            return;
        }

        // update light parameters
        public virtual void UpdateLight(EffectParameter p_effectParameter, Matrix p_world)
        {
            p_effectParameter.StructureMembers["position"].SetValue(new Vector4(m_position, 1));
            p_effectParameter.StructureMembers["falloffStart"].SetValue(m_falloffStart);
            p_effectParameter.StructureMembers["falloffEnd"].SetValue(m_falloffEnd);
            p_effectParameter.StructureMembers["color"].SetValue(new Vector4(m_color, 1));
        }
    }
}
